//  object类型 只是粗略声明一个变量的类型是对象， 不关心对象内部的属性情况
const obj: object = {
    
}

// 实际开发中更关心对象内部的结构（形状 shape）
//  interface接口 可以用于规定对象中的形状

//  interface 接口名称 {属性名:类型; ....}

// 接口名称 单词（首字母大写）前面+ 大写I

interface IPerson {
    name: String;
    age: number;
}

const p: IPerson = {
    name: "aaa",
    age: 20
}

// 如果 属性的类型不匹配， 编译报错
// const p1:IPerson = {
//     name: 111,
//     age: 20
// }

// 缺少必须属性报错
// const p1:IPerson = {
//     name: 'jack',
// }

// 多了属性也会报错
// const p2:IPerson = {
//     name: 'jack',
//     age: 30,
//     girlfriend: '老王'
// }



// 2.可选属性
interface IPerson1 {
    name: string;
    age: number;
    // ？表示可以是字符串类型也可以是undefined
    gfriend?: string;
}

const p2: IPerson1 = {
    name: 'jack',
    age: 30,
    gfriend: '老王'
}

const p3: IPerson1 = {
    name: 'jack',
    age: 30,
}

// 3.任意属性
interface IPerson2 {
    name: String;
    // 属性名要么是字符串要么是symbol
    [propName: string]: any;  // any 任意类型 
}

const p4: IPerson2 = {
    name: "err",
    // 属性名要么是字符串要么是symbol
    age: 1, // any 任意类型 
    gfriend: "hj"
}


// 定义了任意属性，那么确定属性和可选属性的类型都必须被它包含
interface IPerson4 {
    // name:String;
    // 属性名要么是字符串要么是symbol
    // 一般就只写着一条
    [propName: string]: string;  // any 任意类型 
}

interface IPerson5 {
    name: string;
    age?: number;      // 可选属性 写成  基本类型 | undefined 的联合类型 
    age1: number | undefined;
    [propName: string]: number | string | undefined;     // 如果接口中有了可选类型， 任意类型也包含的话 ， 就要加上undefined 的联合类型
}

// 只读属性 
interface IPerson6 {
    readonly id: number;
    name: string;
    age?: number;  // any 任意类型 
}

const p6:IPerson6 = {
    id: 123,
    name: "rose",
}

// p6.id = 100//编译失败